﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

namespace MicroFractal.iTunesBrowser.Controls
{
    /// <summary>
    /// Interaction logic for CoverLibrary.xaml
    /// </summary>
    public partial class CoverLibrary : UserControl
    {

        #region Constructor

        public CoverLibrary()
        {
            InitializeComponent();
            this.SizeChanged += new SizeChangedEventHandler(CoverLibrary_SizeChanged);
            Covers = new System.Collections.ObjectModel.ObservableCollection<Cover>();
            Covers.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Covers_CollectionChanged);
        }

        #endregion

        #region Properties

        private Cover _selectedCover;
        public Cover SelectedCover
        {
            get { return _selectedCover; }
            set
            {
                _selectedCover = value;
                SelectCover(SelectedIndex);
                SelectReflectionCover(SelectedIndex);
            }
        }

        public int SelectedIndex
        {
            get { return Covers.IndexOf(_selectedCover); }
            set
            {
                SelectedCover = Covers[value];
            }
        }

        public System.Collections.ObjectModel.ObservableCollection<Cover> Covers { get; set; }

        private string _filter;
        public string Filter
        {
            get
            {
                return _filter;
            }
            set
            {
                _filter = value;
                foreach (Cover c in Covers)
                {
                    if (!c.AlbumName.Contains(_filter) && !c.ArtistName.Contains(_filter))
                    {
                        int i = this.canvasCoverFlow.Children.IndexOf(c);
                        if (i > -1)
                        {
                            this.canvasCoverFlow.Children.RemoveAt(i);
                            this.canvasReflection.Children.RemoveAt(i);
                        }
                    }
                    else
                    {
                        if (!this.canvasCoverFlow.Children.Contains(c))
                        {
                            this.canvasCoverFlow.Children.Add(c);
                            this.canvasReflection.Children.Add((Cover)c.Clone());
                        }
                    }
                }
                if (this.canvasCoverFlow.Children.Count > 0)
                    SelectedIndex = 0;
            }
        }
    
        #endregion

        #region Controls Events

        void CoverLibrary_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            SelectCover(SelectedIndex);
            SelectReflectionCover(SelectedIndex);
        }

        void Covers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                foreach (Cover c in e.NewItems)
                {
                    c.MouseLeftButtonDown += new MouseButtonEventHandler(c_MouseLeftButtonDown);
                    //TODO Ver que efecto darle cuando se pasa el mouse sobre un Cover
                    //c.MouseEnter += new MouseEventHandler(c_MouseEnter);
                    //c.MouseLeave += new MouseEventHandler(c_MouseLeave);
                    this.canvasCoverFlow.Children.Add(c);
                    this.canvasReflection.Children.Add((Cover)c.Clone());
                }
                if (!_updating)
                    SelectedIndex = Covers.Count - 1;
            }
            else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
            {
                foreach (Cover c in e.OldItems)
                {
                    this.canvasCoverFlow.Children.Remove(c);
                    this.canvasReflection.Children.Remove(c);
                }
            }
            else if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset)
            {
                ClearLibrary();
            }
        }

        void c_MouseLeave(object sender, MouseEventArgs e)
        {
            RemoveFocus((Cover)sender);
        }

        void c_MouseEnter(object sender, MouseEventArgs e)
        {
            if (!sender.Equals(_selectedCover))
                SetFocus((Cover)sender);
        }

        private void SetFocus(Cover index)
        {
            Cover reflec = (Cover)canvasReflection.Children[Covers.IndexOf(index)];

            Storyboard s = (Storyboard)index.canvasCover.Resources["FocusAnim"];
            Storyboard s2 = (Storyboard)reflec.canvasCover.Resources["FocusAnim"];

            Point p = reflec.canvasCover.PointToScreen(new Point(0, 0));
            p = this.canvasReflection.PointFromScreen(p);

            ((DoubleAnimation)s2.Children[0]).From = 50;
            ((DoubleAnimation)s2.Children[0]).To = 20;

            s.Begin(index);
            s2.Begin(((Cover)canvasReflection.Children[Covers.IndexOf(index)]));
        }

        private void RemoveFocus(Cover index)
        {
            Storyboard s = (Storyboard)index.canvasCover.Resources["UnFocusAnim"];
            Storyboard s2 = (Storyboard)((Cover)canvasReflection.Children[Covers.IndexOf(index)]).canvasCover.Resources["UnFocusAnim"];

            //Point p = index.canvasCover.PointToScreen(new Point(0, 0));
            //p = this.canvasCoverFlow.PointFromScreen(p);
            
            //((DoubleAnimation)s.Children[1]).From = p.X;
            //((DoubleAnimation)s.Children[1]).To = p.X;

            if (!index.Equals(_selectedCover))
            {
                ((DoubleAnimation)s2.Children[0]).To = 50;
                s2.Begin(((Cover)canvasReflection.Children[Covers.IndexOf(index)]));
            }

            s.Begin(index);
        }

        private void ClearLibrary()
        {
            this.canvasCoverFlow.Children.Clear();
            this.canvasReflection.Children.Clear();
            _selectedCover = null;
            lblAlbum.Content = "";
            lblArtist.Content = "";
        }

        void c_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            int index = Covers.IndexOf((Cover)sender);
            if (sender.Equals(_selectedCover))
            {
                ((Cover)sender).Flip();
            }
            else
            {
                _selectedCover = (Cover)sender;
                SelectCover(index);
                SelectReflectionCover(index);
            }
        }

        #endregion

        #region Events

        public event EventHandler SelectedIndexChange;

        protected void OnSelectedIndexChange()
        {
            if (SelectedIndexChange != null)
            {
                SelectedIndexChange(this, EventArgs.Empty);
            }
        }

        #endregion

        #region Methods

        private bool _updating = false;

        public void BeginUpdate()
        {
            _updating = true;
            Label l = new Label();
            l.Content = "Loading...";
            l.HorizontalAlignment = HorizontalAlignment.Center;
            l.VerticalAlignment = VerticalAlignment.Center;
            l.Foreground = Brushes.White;
            l.Width = 300;
            l.Height = 300;
            this.canvasCoverFlow.Children.Add(l);
            Canvas.SetZIndex(l, 100);
            Canvas.SetLeft(l, 100);
            Canvas.SetTop(l, 100);
        }

        public void EndUpdate()
        {
            if (!_updating)
                return;

            if (_selectedCover == null)
                SelectedIndex = 0;

            _updating = false;
        }

        private void SelectCover(int index)
        {
            //TODO Mejorar esto que es re lento
            Canvas control = canvasCoverFlow;
            // Setup

            if (index == -1 && this.Covers.Count > 0)
                index = this.Covers.Count / 2;

            if (index == -1)
                return;

            double coverwidth = 240;
            double coverwidth2 = coverwidth / 4;
            double center = (control.ActualWidth - coverwidth) / 2;

            double perspectivetop = 25;
            double perspectivebotton = 10;
            double scaley = 0.8;
            double scalex = scaley * (1.0 - perspectivetop / coverwidth);
            double offset = coverwidth * 0.8;

            // Layout
            for (int i = 0; i < control.Children.Count; i++)
            {
                Cover cover = (Cover)control.Children[i];
                if (i < index)
                {
                    if (_updating || center - (offset + ((index - 1) - i) * coverwidth2) > -coverwidth)
                    {
                        Storyboard sb = (Storyboard)cover.canvasCover.Resources["anim"];
                        ((DoubleAnimation)sb.Children[0]).To = scalex;
                        ((DoubleAnimation)sb.Children[1]).To = scaley;
                        ((DoubleAnimation)sb.Children[2]).To = -perspectivebotton;
                        ((DoubleAnimation)sb.Children[3]).To = center - (offset + ((index - 1) - i) * coverwidth2);
                        ((PointAnimation)sb.Children[4]).To = new Point(0, 0);
                        ((PointAnimation)sb.Children[5]).To = new Point(coverwidth, perspectivetop);
                        sb.Begin(cover);
                    }
                    Canvas.SetZIndex(cover, i + Covers.Count);
                    //else
                    //{
                    //    Canvas.SetLeft(cover.canvasCover, center - (offset + ((index - 1) - i) * coverwidth2));
                    //}
                }
                else if (i > index)
                {
                    int ii = (i - index - 1);
                    if (_updating || center + (offset + ii * coverwidth2) < control.ActualWidth)
                    {
                        Storyboard sb = (Storyboard)cover.canvasCover.Resources["anim"];
                        ((DoubleAnimation)sb.Children[0]).To = scalex;
                        ((DoubleAnimation)sb.Children[1]).To = scaley;
                        ((DoubleAnimation)sb.Children[2]).To = perspectivebotton;
                        ((DoubleAnimation)sb.Children[3]).To = center + (offset + ii * coverwidth2);
                        ((PointAnimation)sb.Children[4]).To = new Point(0, perspectivetop);
                        ((PointAnimation)sb.Children[5]).To = new Point(coverwidth, perspectivebotton);
                        sb.Begin(cover);
                    }
                    Canvas.SetZIndex(cover, (control.Children.Count - 1) - ii + Covers.Count);
                    //else
                    //{
                        //Canvas.SetLeft(cover, center + (offset + (i - index - 1) * coverwidth2));
                        //Canvas.SetLeft(cover.canvasCover,center + (offset + (i - index - 1) * coverwidth2));
                        //Canvas.SetLeft(cover.imgCover, center + (offset + (i - index - 1) * coverwidth2));
                    //}
                }
                else
                {
                    Storyboard sb = (Storyboard)cover.canvasCover.Resources["anim"];
                    ((DoubleAnimation)sb.Children[0]).To = 1;
                    ((DoubleAnimation)sb.Children[1]).To = 1;
                    ((DoubleAnimation)sb.Children[2]).To = 0;
                    ((DoubleAnimation)sb.Children[3]).To = center;
                    ((PointAnimation)sb.Children[4]).To = new Point(0, 0);
                    ((PointAnimation)sb.Children[5]).To = new Point(coverwidth, 0);
                    sb.Begin(cover);
                    Canvas.SetZIndex(cover, control.Children.Count * 2);
                }
            }

            if (index >= 0 && control.Children.Count > index)
            {
                lblArtist.Content = ((Cover)control.Children[index]).ArtistName;
                lblAlbum.Content = ((Cover)control.Children[index]).AlbumName;
                OnSelectedIndexChange();
            }
        }

        private void SelectReflectionCover(int index)
        {

            Canvas control = canvasReflection;
            // Setup

            if (index == -1 && this.Covers.Count > 0)
                index = this.Covers.Count / 2;

            if (index == -1)
                return;

            double coverwidth = 240;
            double coverwidth2 = coverwidth / 4;
            double center = (control.ActualWidth - coverwidth) / 2;

            double perspectivetop = 25;
            double perspectivebotton = 10;
            double scaley = 0.8;
            double scalex = scaley * (1.0 - perspectivetop / coverwidth);
            double offset = coverwidth * 0.8;

            // Layout
            for (int i = 0; i < control.Children.Count; i++)
            {
                if (control.Children[i] is Label)
                    return;

                Cover cover = (Cover)control.Children[i];
                if (i < index)
                {
                    if (_updating || center - (offset + ((index - 1) - i) * coverwidth2) > -coverwidth)
                    {
                        Storyboard sb = (Storyboard)cover.canvasCover.Resources["reflecAnim"];
                        ((DoubleAnimation)sb.Children[0]).To = scalex;
                        ((DoubleAnimation)sb.Children[1]).To = scaley;
                        ((DoubleAnimation)sb.Children[2]).To = perspectivebotton;
                        ((DoubleAnimation)sb.Children[3]).To = center - (offset + ((index - 1) - i) * coverwidth2);
                        ((DoubleAnimation)sb.Children[4]).To = 50;
                        ((PointAnimation)sb.Children[5]).To = new Point(0, 0);
                        ((PointAnimation)sb.Children[6]).To = new Point(coverwidth, perspectivetop);
                        sb.Begin(cover);
                    }
                    Canvas.SetZIndex(cover, i);
                }
                else if (i > index)
                {
                    int ii = (i - index - 1);
                    if (_updating || center + (offset + ii * coverwidth2) < control.ActualWidth)
                    {
                        Storyboard sb = (Storyboard)cover.canvasCover.Resources["reflecAnim"];
                        ((DoubleAnimation)sb.Children[0]).To = scalex;
                        ((DoubleAnimation)sb.Children[1]).To = scaley;
                        ((DoubleAnimation)sb.Children[2]).To = -perspectivebotton;
                        ((DoubleAnimation)sb.Children[3]).To = center + (offset + ii * coverwidth2);
                        ((DoubleAnimation)sb.Children[4]).To = 50;
                        ((PointAnimation)sb.Children[5]).To = new Point(0, perspectivetop);
                        ((PointAnimation)sb.Children[6]).To = new Point(coverwidth, 0);
                        sb.Begin(cover);
                    }
                    Canvas.SetZIndex(cover, (control.Children.Count - 1) - ii);
                }
                else
                {
                    Storyboard sb = (Storyboard)cover.canvasCover.Resources["reflecAnim"];
                    ((DoubleAnimation)sb.Children[0]).To = 1;
                    ((DoubleAnimation)sb.Children[1]).To = 1;
                    ((DoubleAnimation)sb.Children[2]).To = 0;
                    ((DoubleAnimation)sb.Children[3]).To = center;
                    ((DoubleAnimation)sb.Children[4]).To = 0;
                    ((PointAnimation)sb.Children[5]).To = new Point(0, 0);
                    ((PointAnimation)sb.Children[6]).To = new Point(coverwidth, 0);
                    sb.Begin(cover);
                    Canvas.SetZIndex(cover, control.Children.Count);
                }
            }
        }

        #endregion

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            Filter = ((TextBox)sender).Text;
        }
    }
}
